
# 普通函数
def function():
    return 1


# 生成器函数
def generator():
    yield 1

# 异步函数（协程）
async def async_function():
    return 1

# 异步生成器
async def async_generator():
    yield 1

async def await_coroutine():
    result = await async_function()
    print(result)

import types

# print(type(function) is types.FunctionType)
# print(type(generator()) is types.GeneratorType)
# print(type(async_function()) is types.CoroutineType)
# print(type(async_function()) is types.AsyncGeneratorType)

# print(async_function().send(None))  # StopIteration: 1

# 因为生成器/协程在正常返回退出时会抛出一个StopIteration异常，
# 而原来的返回值会存放在StopIteration对象的value属性中，
# 通过以下捕获可以获取协程真正的返回值：

def run(coroutine):
    try:
        coroutine.send(None)
    except StopIteration as e:
        return e.value

run(await_coroutine())

# 要注意的是，await语法只能出现在通过async修饰的函数中，否则会报SyntaxError错误。
# 而且await后面的对象需要是一个Awaitable，或者实现了相关的协议。
# 查看Awaitable抽象类的代码，表明了只要一个类实现了__await__方法，那么通过它构造出来的实例就是一个Awaitable：
'''
class Awaitable(metaclass=ABCMeta):
    __slots__ = ()

    @abstractmethod
    def __await__(self):
        yield

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Awaitable:
            return _check_methods(C, "__await__")
        return NotImplemented
'''

# Coroutine类也继承了Awaitable,并且实现了sedn,throw,close.所以await一个调用异步函数返回的协程是合法的
'''
class Coroutine(Awaitable):
    __slots__ = ()

    @abstractmethod
    def send(self, value):
        ...

    @abstractmethod
    def throw(self, typ, val=None, tb=None):
        ...

    def close(self):
        ...
        
    @classmethod
    def __subclasshook__(cls, C):
        if cls is Coroutine:
            return _check_methods(C, '__await__', 'send', 'throw', 'close')
        return NotImplemented
'''